package com.global.crypto.utils;

import com.global.crypto.enums.AsymmetricAlgorithm;
import com.global.crypto.enums.SymmetricAlgorithm;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;
import java.security.spec.*;
import java.util.Base64;

/**
 * 全局加密算法与密钥生成工具类
 */
public class CryptoUtils {

    // 静态初始化块，添加 BouncyCastle 安全提供者，以支持更多加密算法
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 支持的哈希算法枚举
     */
    public enum HashAlgorithm {
        MD5("MD5"),                   // 消息摘要算法，128 位
        SHA1("SHA-1"),                // 安全哈希算法 1，160 位
        SHA256("SHA-256"),            // SHA-2 256 位
        SHA384("SHA-384"),            // SHA-2 384 位
        SHA512("SHA-512"),            // SHA-2 512 位
        SHA3_256("SHA3-256"),         // SHA3 256 位
        SHA3_384("SHA3-384"),         // SHA3 384 位
        SHA3_512("SHA3-512"),         // SHA3 512 位
        RIPEMD128("RIPEMD128"),       // RIPE 消息摘要 128 位
        RIPEMD160("RIPEMD160"),       // RIPE 消息摘要 160 位
        RIPEMD256("RIPEMD256"),       // RIPE 消息摘要 256 位
        GOST3411("GOST3411"),         // 俄罗斯 GOST 哈希算法
        WHIRLPOOL("Whirlpool");       // Whirlpool 哈希算法

        private final String name;

        HashAlgorithm(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }
    }

    /**
     * 生成指定对称算法和密钥长度的密钥
     */
    public static SecretKey generateSymmetricKey(SymmetricAlgorithm algorithm, int keySize)
            throws NoSuchAlgorithmException, InvalidParameterException {
        // 校验密钥长度是否在允许范围内
        if (keySize < algorithm.getMinKeySize() || keySize > algorithm.getMaxKeySize()) {
            throw new InvalidParameterException(String.format(
                    "密钥长度必须在 %d 到 %d 比特之间，当前算法：%s",
                    algorithm.getMinKeySize(), algorithm.getMaxKeySize(), algorithm.getName()));
        }
        // 获取密钥生成器并生成密钥
        KeyGenerator keyGen = KeyGenerator.getInstance(algorithm.getName());
        keyGen.init(keySize);
        return keyGen.generateKey();
    }

    /**
     * 生成指定非对称算法和密钥长度的密钥对（公钥+私钥）
     */
    public static KeyPair generateAsymmetricKeyPair(AsymmetricAlgorithm algorithm, int keySize)
            throws NoSuchAlgorithmException, InvalidParameterException {
        if (keySize < algorithm.getMinKeySize() || keySize > algorithm.getMaxKeySize()) {
            throw new InvalidParameterException(String.format(
                    "密钥长度必须在 %d 到 %d 比特之间，当前算法：%s",
                    algorithm.getMinKeySize(), algorithm.getMaxKeySize(), algorithm.getName()));
        }
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm.getName());
        keyGen.initialize(keySize);
        return keyGen.generateKeyPair();
    }

    /**
     * 使用对称算法加密数据
     */
    public static byte[] encryptSymmetric(SymmetricAlgorithm algorithm, String mode, String padding,
                                          SecretKey key, byte[] iv, byte[] data) throws GeneralSecurityException {
        String transformation = algorithm.getName() + "/" + mode + "/" + padding;
        Cipher cipher = Cipher.getInstance(transformation);
        if (iv != null) {
            IvParameterSpec ivSpec = new IvParameterSpec(iv);
            cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
        } else {
            cipher.init(Cipher.ENCRYPT_MODE, key);
        }
        return cipher.doFinal(data);
    }

    /**
     * 使用对称算法解密数据
     */
    public static byte[] decryptSymmetric(SymmetricAlgorithm algorithm, String mode, String padding,
                                          SecretKey key, byte[] iv, byte[] encryptedData) throws GeneralSecurityException {
        String transformation = algorithm.getName() + "/" + mode + "/" + padding;
        Cipher cipher = Cipher.getInstance(transformation);
        if (iv != null) {
            IvParameterSpec ivSpec = new IvParameterSpec(iv);
            cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
        } else {
            cipher.init(Cipher.DECRYPT_MODE, key);
        }
        return cipher.doFinal(encryptedData);
    }

    /**
     * 使用非对称算法（公钥）加密数据
     */
    public static byte[] encryptAsymmetric(AsymmetricAlgorithm algorithm, String padding,
                                           PublicKey publicKey, byte[] data) throws GeneralSecurityException {
        // 修改transformation格式，确保符合Java加密体系要求
        String transformation = algorithm.getName() + "/ECB/" + padding;
        Cipher cipher = Cipher.getInstance(transformation);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }

    /**
     * 使用非对称算法（私钥）解密数据
     */
    public static byte[] decryptAsymmetric(AsymmetricAlgorithm algorithm, String padding,
                                           PrivateKey privateKey, byte[] encryptedData) throws GeneralSecurityException {
        // 修改transformation格式，确保符合Java加密体系要求
        String transformation = algorithm.getName() + "/ECB/" + padding;
        Cipher cipher = Cipher.getInstance(transformation);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(encryptedData);
    }

    /**
     * 生成数据的哈希值
     */
    public static byte[] generateHash(HashAlgorithm algorithm, byte[] data) throws NoSuchAlgorithmException {
        MessageDigest digest = MessageDigest.getInstance(algorithm.getName());
        return digest.digest(data);
    }

    /**
     * 生成指定长度的随机初始化向量（IV）
     */
    public static byte[] generateIV(int size) {
        byte[] iv = new byte[size];
        new SecureRandom().nextBytes(iv);
        return iv;
    }

    /**
     * 将密钥对象转换为 Base64 编码字符串，便于存储或传输
     */
    public static String keyToString(Key key) {
        return Base64.getEncoder().encodeToString(key.getEncoded());
    }

    /**
     * 将 Base64 字符串还原为对称密钥对象
     */
    public static SecretKey stringToSecretKey(SymmetricAlgorithm algorithm, String keyStr) {
        byte[] decodedKey = Base64.getDecoder().decode(keyStr);
        return new SecretKeySpec(decodedKey, 0, decodedKey.length, algorithm.getName());
    }

    /**
     * 将 Base64 字符串还原为非对称公钥对象
     */
    public static PublicKey stringToPublicKey(AsymmetricAlgorithm algorithm, String keyStr) throws GeneralSecurityException {
        byte[] decodedKey = Base64.getDecoder().decode(keyStr);
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm.getName());
        return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
    }

    /**
     * 将 Base64 字符串还原为非对称私钥对象
     */
    public static PrivateKey stringToPrivateKey(AsymmetricAlgorithm algorithm, String keyStr) throws GeneralSecurityException {
        byte[] decodedKey = Base64.getDecoder().decode(keyStr);
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm.getName());
        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(decodedKey));
    }
}
